// REVISED FILE: dbms/CompilerUtil.java
package com.dbms;

import com.dbms.common.SqlError;
import com.dbms.parser.ExecutionPlanGenerator;
import com.dbms.parser.SqlLexer;
import com.dbms.parser.SqlParser;
import com.dbms.parser.Token;
import com.dbms.parser.ast.*; // Import all from ast
import com.dbms.catalogInParse.Column;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 编译器前端工具类，用于演示和测试从SQL文本到执行计划的完整流程。
 * <p>
 * 这个类整合了词法分析、语法分析、语义分析和逻辑执行计划生成这几个编译器的核心前端阶段。
 * 它作为一个独立的工具，可以处理SQL字符串，并打印出每个阶段的详细输出，
 * 非常适合用于教学、演示或调试编译器前端的各个部分。
 * <p>
 * [V2 - 已修正]
 * 1. 增加了对 DeleteNode 的语义检查，以验证表存在性.
 */
public class CompilerUtil {

    /**
     * 一个简化的、仅用于语义分析阶段的内存中目录（Catalog）。
     * 它在处理过程中跟踪已创建的表和列的元数据，以便进行后续的语义检查，
     * 例如检查表是否存在、列是否存在、类型是否匹配等。
     */
    private final com.dbms.catalogInParse.Catalog semanticCatalog;

    /**
     * CompilerUtil的构造函数。
     * 初始化一个空的语义目录。
     */
    public CompilerUtil() {
        this.semanticCatalog = new com.dbms.catalogInParse.Catalog();
    }

    /**
     * 处理单条或多条SQL语句的核心方法。
     * 依次执行词法分析、语法分析、语义分析和执行计划生成，并打印每一步的结果。
     * @param sql 包含一条或多条SQL语句的字符串。
     */
    public void processSql(String sql) {
        System.out.println("=========================================================");
        System.out.println("Processing SQL:\n" + sql.trim());
        System.out.println("---------------------------------------------------------");

        // --- 1. 词法分析 (Lexical Analysis) ---
        // 将原始SQL字符串分解成Token流。
        System.out.println("1. Lexical Analysis (Tokens):");
        SqlLexer lexer = new SqlLexer(sql);
        List<Token> tokens = lexer.tokenize();
        // 检查词法分析过程中是否有错误
        if (!lexer.getErrors().isEmpty()) {
            System.out.println("  [LEXICAL ERROR] Found illegal characters:");
            for (SqlError error : lexer.getErrors()) {
                System.out.println("  " + error);
            }
            System.out.println("=========================================================\n");
            return; // 遇到词法错误，终止处理
        }
        // 打印生成的Token流
        tokens.forEach(token -> System.out.println("  " + String.format("[%-10s, %-20s, 行:%-3d, 列:%-3d]",
                token.getType(), "'" + token.getLexeme() + "'", token.getPosition().getLine(), token.getPosition().getColumn())));
        System.out.println("---------------------------------------------------------");

        // --- 2. 语法分析 (Syntax Analysis) ---
        // 将Token流转换成抽象语法树（AST）。
        System.out.println("2. Syntax Analysis (Abstract Syntax Tree):");
        SqlParser parser = new SqlParser(tokens);
        List<StatementNode> astNodes = parser.parseAll();
        // 检查语法分析过程中是否有错误
        if (!parser.getErrors().isEmpty()) {
            System.out.println("  [SYNTAX ERROR] Failed to parse statement:");
            for (SqlError error : parser.getErrors()) {
                System.out.println("  " + error);
            }
            System.out.println("=========================================================\n");
            return; // 遇到语法错误，终止处理
        }
        // 打印生成的AST
        astNodes.forEach(ast -> System.out.println(ast.toString()));
        System.out.println("---------------------------------------------------------");

        // --- 3. 语义分析 (Semantic Analysis) & 4. 执行计划生成 (Execution Plan Generation) ---
        System.out.println("3. Semantic Analysis & 4. Execution Plan:");
        ExecutionPlanGenerator planGenerator = new ExecutionPlanGenerator();
        boolean allSemanticsValid = true;

        // 遍历每一棵AST，分别进行语义检查和计划生成
        for (StatementNode stmt : astNodes) {
            System.out.println("\nAnalyzing statement: " + stmt.getStatementType());
            try {
                // 执行语义检查
                performSemanticChecks(stmt);
                System.out.println("  - Semantic check PASSED.");

                // 如果语义检查通过，则生成执行计划
                String plan = planGenerator.generatePlans(List.of(stmt)).get(0);
                System.out.println("  - Execution Plan:");
                for(String line : plan.lines().collect(Collectors.toList())) {
                    System.out.println("    " + line);
                }

            } catch (SqlError e) {
                // 捕获并打印语义错误
                System.out.println("  [SEMANTIC ERROR] " + e);
                allSemanticsValid = false;
            }
        }

        if (allSemanticsValid) {
            System.out.println("\nAll statements are semantically valid and plans are generated.");
        } else {
            System.out.println("\nFound semantic errors in one or more statements.");
        }
        System.out.println("=========================================================\n");
    }

    /**
     * 执行语义检查的私有方法。
     * 它根据语句的类型，应用不同的检查规则。
     * @param stmt 要检查的语句的AST节点。
     * @throws SqlError 如果发现语义错误。
     */
    private void performSemanticChecks(StatementNode stmt) throws SqlError {
        if (stmt instanceof CreateTableNode) {
            CreateTableNode node = (CreateTableNode) stmt;
            // 检查表是否已经存在
            if (semanticCatalog.containsTable(node.getTableName())) {
                throw new SqlError(com.dbms.common.Constants.ErrorType.SEMANTIC_ERROR, node.getPosition(), "Table '" + node.getTableName() + "' already exists.");
            }
            // 如果检查通过，将新表的元数据添加到语义目录中，供后续语句使用
            semanticCatalog.createTable(node.getTableName(), node.getColumns());

        } else if (stmt instanceof InsertNode) {
            InsertNode node = (InsertNode) stmt;
            // 检查目标表是否存在
            if (!semanticCatalog.containsTable(node.getTableName())) {
                throw new SqlError(com.dbms.common.Constants.ErrorType.SEMANTIC_ERROR, node.getPosition(), "Table '" + node.getTableName() + "' does not exist.");
            }
            com.dbms.catalogInParse.TableSchema table = semanticCatalog.getTable(node.getTableName());
            List<Column> columns = new ArrayList<>(table.getColumns());
            List<String> values = node.getValues();

            // 检查插入的值的数量是否与表的列数匹配
            if (columns.size() != values.size()) {
                throw new SqlError(com.dbms.common.Constants.ErrorType.SEMANTIC_ERROR, node.getPosition(), "Column count doesn't match value count. Expected " + columns.size() + ", got " + values.size() + ".");
            }

            // 检查每个插入的值的类型是否与对应列的类型兼容
            for (int i = 0; i < columns.size(); i++) {
                Column col = columns.get(i);
                String val = values.get(i);
                if (col.getType().equalsIgnoreCase("INT")) {
                    try {
                        Integer.parseInt(val.replaceAll("^'|'$", ""));
                    } catch (NumberFormatException e) {
                        throw new SqlError(com.dbms.common.Constants.ErrorType.SEMANTIC_ERROR, node.getPosition(), "Type mismatch for column '" + col.getName() + "'. Expected INT, got '" + val + "'.");
                    }
                }
            }

        } else if (stmt instanceof SelectNode) {
            SelectNode node = (SelectNode) stmt;
            // 检查表是否存在
            if (!semanticCatalog.containsTable(node.getTableName())) {
                throw new SqlError(com.dbms.common.Constants.ErrorType.SEMANTIC_ERROR, node.getPosition(), "Table '" + node.getTableName() + "' does not exist.");
            }
            com.dbms.catalogInParse.TableSchema table = semanticCatalog.getTable(node.getTableName());

            // 检查SELECT列表中的每一列是否存在于表中
            for (Object selectedCol : node.getColumns()) {
                if (selectedCol instanceof String && !selectedCol.equals("*")) {
                    if (!table.hasColumn((String) selectedCol)) {
                        throw new SqlError(com.dbms.common.Constants.ErrorType.SEMANTIC_ERROR, node.getPosition(), "Column '" + selectedCol + "' not found in table '" + node.getTableName() + "'.");
                    }
                }
            }
            // 检查WHERE子句中的列是否存在
            if (node.getWhereClause() != null) {
                String whereCol = node.getWhereClause().getLeftOperand();
                if (!table.hasColumn(whereCol)) {
                    throw new SqlError(com.dbms.common.Constants.ErrorType.SEMANTIC_ERROR, node.getPosition(), "Column '" + whereCol + "' in WHERE clause not found in table '" + node.getTableName() + "'.");
                }
            }
        } else if (stmt instanceof DeleteNode) { // 【新增】对DELETE语句的语义检查
            DeleteNode node = (DeleteNode) stmt;
            // 检查表是否存在
            if (!semanticCatalog.containsTable(node.getTableName())) {
                throw new SqlError(com.dbms.common.Constants.ErrorType.SEMANTIC_ERROR, node.getPosition(), "Table '" + node.getTableName() + "' does not exist.");
            }
        }
    }
}